import { isDef, isNumber, isPlainObject, isPromise } from './validator'
import { canIUseGroupSetData, canIUseNextTick } from './version'
import CryptoJS from 'crypto-js'

export function range (num, min, max) {
  return Math.min(Math.max(num, min), max)
}

export function md5 (str, lower = true) {
  const encode = CryptoJS.MD5(str).toString()
  return lower ? encode.toLowerCase() : encode.toUpperCase()
}

export function nextTick (cb) {
  if (canIUseNextTick()) {
    wx.nextTick(cb)
  } else {
    setTimeout(() => {
      cb()
    }, 1000 / 30)
  }
}
let systemInfo
export function getSystemInfoSync () {
  if (systemInfo == null) {
    systemInfo = wx.getSystemInfoSync()
  }
  return systemInfo
}
export function addUnit (value) {
  if (!isDef(value)) {
    return undefined
  }
  value = String(value)
  return isNumber(value) ? `${value}px` : value
}
export function requestAnimationFrame (cb) {
  const systemInfo = getSystemInfoSync()
  if (systemInfo.platform === 'devtools') {
    return setTimeout(() => {
      cb()
    }, 1000 / 30)
  }
  return wx
    .createSelectorQuery()
    .selectViewport()
    .boundingClientRect()
    .exec(() => {
      cb()
    })
}
export function pickExclude (obj, keys) {
  if (!isPlainObject(obj)) {
    return {}
  }
  return Object.keys(obj).reduce((prev, key) => {
    if (!keys.includes(key)) {
      prev[key] = obj[key]
    }
    return prev
  }, {})
}
export function getRect (context, selector) {
  return new Promise((resolve) => {
    wx.createSelectorQuery()
      .in(context)
      .select(selector)
      .boundingClientRect()
      .exec((rect = []) => resolve(rect[0]))
  })
}
export function getAllRect (context, selector) {
  return new Promise((resolve) => {
    wx.createSelectorQuery()
      .in(context)
      .selectAll(selector)
      .boundingClientRect()
      .exec((rect = []) => resolve(rect[0]))
  })
}
export function groupSetData (context, cb) {
  if (canIUseGroupSetData()) {
    context.groupSetData(cb)
  } else {
    cb()
  }
}
export function toPromise (promiseLike) {
  if (isPromise(promiseLike)) {
    return promiseLike
  }
  return Promise.resolve(promiseLike)
}
export function getCurrentPage () {
  // eslint-disable-next-line no-undef
  const pages = getCurrentPages()
  return pages[pages.length - 1]
}

export function formatNumber (n) {
  const str = n.toString()
  return str[1] ? str : `0${str}`
}

export function formatDateTime (date) {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()

  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()

  const t1 = [year, month, day].map(formatNumber).join('/')
  const t2 = [hour, minute, second].map(formatNumber).join(':')

  return `${t1} ${t2}`
}

export function formatDate (timestamp) {
  var date = new Date(timestamp)
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()

  return [year, month, day].map(formatNumber).join('-')
}

export function formatTime (timestamp) {
  var date = new Date(timestamp)
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()

  return [year, month, day].map(formatNumber).join('-')
}

export function randomString (length) {
  let text = ''
  const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  for (let i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length))
  }
  return text
}

/**
 * 产生随机整数，包含下限值，包括上限值
 * @param {Number} lower 下限
 * @param {Number} upper 上限
 * @return {Number} 返回在下限到上限之间的一个随机整数
 */
export function random (lower, upper) {
  return Math.floor(Math.random() * (upper - lower + 1)) + lower
}

export function getTimestamp () {
  const date = new Date()
  const timeString = Date.parse(date).toString()
  return timeString.slice(0, timeString.length - 3)
}

/*
 *  将对象转变为class字符串
 */
export function formatClasses (obj) {
  let classesStr = ''
  for (let className in obj) {
    if (obj.hasOwnProperty(className) && !!obj[className]) classesStr += className
  }
  return classesStr
}

/*
 * 将对象转变为style字符串，对象属性的camel命名会转换为中划线命名
 */
export function formatStyles (obj) {
  let stylesStr = ''
  for (let styleName in obj) {
    if (obj.hasOwnProperty(styleName)) stylesStr += `${styleName.replace(/([A-Z])/g, '-$1').toLowerCase()}:${px2rpx(obj[styleName])};`
  }
  return stylesStr
}

/**
 * 处理富文本里的图片宽度自适应
 * 1.去掉img标签里的style、width、height属性
 * 2.img标签添加style属性：max-width:100%;height:auto
 * 3.修改所有style里的width属性为max-width:100%
 * 4.去掉<br/>标签
 * @param html
 * @returns {void|string|*}
 */
export function formatRichText (html) {
  let newContent = html.replace(/<img[^>]*>/gi, function (match, capture) {
    match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '')
    match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '')
    match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '')
    return match
  })
  newContent = newContent.replace(/style="[^"]+"/gi, function (match, capture) {
    match = match.replace(/width:[^;]+;/gi, 'max-width:100%;').replace(/width:[^;]+;/gi, 'max-width:100%;')
    return match
  })
  newContent = newContent.replace(/<br[^>]*\/>/gi, '')
  newContent = newContent.replace(/<img/gi, '<img style="max-width:100%;height:auto;display:block;margin-top:0;margin-bottom:0;"')
  return newContent
}

/*
 *  将对象转变为class字符串
 */
export function getSystemInfo (obj) {
  let classesStr = ''
  for (let className in obj) {
    if (obj.hasOwnProperty(className) && !!obj[className]) classesStr += className
  }
  return classesStr
}

let windowWidth
(async () => {
  let systemInfo = await wx.getSystemInfoSync()
  windowWidth = systemInfo.windowWidth
}).call(this)

export function px2rpx (str) {
  if (/rpx/.test(str)) return str
  else if (/px/.test(str)) {
    let val = str.substring(0, str.indexOf('px'))
    /* 在代码中硬编码时，所有px单位都是以375px为整个屏幕宽度作为参照，所以这里需要转换一下 */
    val = val * windowWidth / 375
    return `${(val - 0) * 750 / windowWidth}rpx`
  } else return str
}

export default {
  formatNumber,
  formatDate,
  formatTime,
  randomString,
  random,
  getTimestamp,
  formatRichText
}
